package org.example;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

public class App {
    public static void main(String[] args) throws Exception {
        // 可以通过传递参数来调用以下方法
        readFile("/core.xml");
        uploadFile("./upload.txt", "/testDir/");
        downloadFile("/test/core-site.xml", ".");
        createFile("/hello2.txt", "Hello Hadoop".getBytes());
        createDir("/test1");
        renameFile("/test1", "/testDir");
        deleteFile("/test");
        fileLocation("/hello.txt");
    }

    static FileSystem getFileSystem() throws Exception {
        // 获取 hdfs 地址
        URI uri = new URI("hdfs://192.168.134.130:9000/");
        // 获取 fileSystem 对象
        return FileSystem.get(uri, new Configuration(), "root");
    }


    /**
     * 用于打印文件系统中特定路径下的文件状态信息。
     */
    private static void printFileStatus(FileSystem fileSystem, Path dst, String message) throws IOException {
        // 打印传入的消息，通常用于标识当前打印的状态是上传前还是上传后等。
        System.out.println(message);
        // 获取指定路径下的文件状态数组。
        FileStatus[] files = fileSystem.listStatus(dst);
        // 遍历文件状态数组，打印每个文件的路径。
        for (FileStatus file : files) {
            System.out.println(file.getPath());
        }
    }
    /**
     * 对指定路径文件进行读取
     */
    public static void readFile(String filePath) throws Exception {
        FileSystem fileSystem = getFileSystem();
        FSDataInputStream open = fileSystem.open(new Path(filePath));
        IOUtils.copyBytes(open, System.out, 1024, false);
        IOUtils.closeStream(open);
    }

    /**
     * 上传文件。
     *
     * @throws Exception 如果在获取文件系统、获取文件状态或执行上传操作时发生错误，则抛出异常。
     */
    public static void uploadFile(String sourcePath, String destinationPath) throws Exception {
        FileSystem fileSystem = getFileSystem();
        Path src = new Path(sourcePath);
        Path dst = new Path(destinationPath);
        printFileStatus(fileSystem, dst, "=============上传之前=============");
        fileSystem.copyFromLocalFile(src, dst);
        printFileStatus(fileSystem, dst, "=============上传之后=============");
    }

    /**
     * 下载文件。
     *
     * @throws Exception 如果在获取文件系统或执行下载操作时发生错误，则抛出异常。
     */
    public static void downloadFile(String sourcePath, String destinationPath) throws Exception {
        FileSystem fileSystem = getFileSystem();
        Path src = new Path(sourcePath);
        Path dst = new Path(destinationPath);
        fileSystem.copyToLocalFile(src, dst);
    }

    /**
     * 创建文件。
     *
     * @throws Exception 如果在获取文件系统、创建文件或写入文件内容时发生错误，则抛出异常。
     */
    public static void createFile(String filePath, byte[] content) throws Exception {
        FileSystem fileSystem = getFileSystem();
        Path dfs = new Path(filePath);
        FSDataOutputStream fdos = fileSystem.create(dfs);
        fdos.write(content, 0, content.length);
        fdos.close();
    }

    /**
     * 创建目录。
     *
     * @throws Exception 如果在获取文件系统或执行创建目录操作时发生错误，则抛出异常。
     */
    public static void createDir(String dirPath) throws Exception {
        FileSystem fileSystem = getFileSystem();
        Path dfs = new Path(dirPath);
        fileSystem.mkdirs(dfs);
    }

    /**
     * 重命名文件。
     *
     * @throws Exception 如果在获取文件系统或执行重命名操作时发生错误，则抛出异常。
     */
    public static void renameFile(String sourcePath, String destinationPath) throws Exception {
        FileSystem fileSystem = getFileSystem();
        Path frpath = new Path(sourcePath);
        Path topath = new Path(destinationPath);
        boolean isRename = fileSystem.rename(frpath, topath);
        String result = isRename? "成功" : "失败";
        System.out.println("文件重命名的结果是：" + result);
    }

    /**
     * 删除指定文件或目录。
     *
     * @throws Exception 如果在获取文件系统或执行删除操作时发生错误，则抛出异常。
     */
    public static void deleteFile(String filePath) throws Exception {
        FileSystem fileSystem = getFileSystem();
        Path path = new Path(filePath);
        boolean isDeleted = fileSystem.delete(path, true);
        String result = isDeleted? "成功" : "失败";
        System.out.println("删除" + result);
    }

    /**
     * 打印指定文件的块存储位置。
     *
     * @throws Exception 如果在获取文件系统、文件状态或块位置时发生错误，则抛出异常。
     */
    public static void fileLocation(String filePath) throws Exception {
        FileSystem fileSystem = getFileSystem();
        Path path = new Path(filePath);
        FileStatus fileStatus = fileSystem.getFileStatus(path);
        BlockLocation[] blockLocations = fileSystem.getFileBlockLocations(fileStatus, 0, fileStatus.getLen());
        int blockLen = blockLocations.length;
        for (int i = 0; i < blockLen; i++) {
            String[] hosts = blockLocations[i].getHosts();
            System.out.println("BLOCK_" + i + "_Location:" + hosts[0]);
        }
    }
}